#include "ip.h"
#include "icmp.h"
#include "arpcache.h"
#include "rtable.h"
#include "arp.h"

// #include "log.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// initialize ip header 
void ip_init_hdr(struct iphdr *ip, u32 saddr, u32 daddr, u16 len, u8 proto)
{
	ip->version = 4;
	ip->ihl = 5;
	ip->tos = 0;
	ip->tot_len = htons(len);
	ip->id = rand();
	ip->frag_off = htons(IP_DF);
	ip->ttl = DEFAULT_TTL;
	ip->protocol = proto;
	ip->saddr = htonl(saddr);
	ip->daddr = htonl(daddr);
	ip->checksum = ip_checksum(ip);
}

// lookup in the routing table, to find the entry with the same and longest prefix.
// the input address is in host byte order
rt_entry_t *longest_prefix_match(u32 dst)
{
	rt_entry_t *pos, *res = NULL;
	u32 max_mask = 0;
	list_for_each_entry(pos, &rtable, list) {
		if ((pos -> mask & pos -> dest) == (pos -> mask & dst)) {
			printf("%u %u\n", pos->mask, pos->dest);
			if (pos -> mask > max_mask) {
				res = pos;
				max_mask = pos -> mask;
			}
		}
	}
	return res;
}

// send IP packet
//
// Different from forwarding packet, ip_send_packet sends packet generated by
// router itself. This function is used to send ICMP packets.
void ip_send_packet(char *packet, int len)
{
	struct ether_header *eh = (struct ether_header*)packet;
	struct iphdr *ih = packet_to_ip_hdr(packet);
	rt_entry_t *find_rt = longest_prefix_match(ntohl(ih -> daddr));

	if (find_rt == NULL) {
		free(packet);
		return;
	}
	
	u32 next_ip;
	if (find_rt -> gw) {
		next_ip = find_rt -> gw;
	} else {
		next_ip = ntohl(ih -> daddr);
	}
	iface_send_packet_by_arp(find_rt -> iface, next_ip, packet, len);
}
